package cn.gem.rainbow.api;

import cn.gem.rainbow.cfg.restful.ResultCodeEnum;
import cn.gem.rainbow.cfg.websocket.MyWebSocketServer;
import cn.gem.rainbow.pojo.req.TestReq;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;


/**
 * restful风格的请求，只返回json或xml格式的数据，而不返回具体的视图页面
 */
@RestController
public class HelloRest {
    @Autowired
    private ServerProperties serverProperties;


    /**
     * 模拟后端发广播消息 给前端WebSocket所有人
     * @param msg
     * @return
     */
    @GetMapping("/sseSendMsgToAll")
    public String sendAllMessageSSE(String msg){
        MyWebSocketServer.sendAllMessage(msg);
        return msg;
    }

    /**
     * 模拟后端发送单播消息 给前端WebSocket某个人
     * @param userId
     * @param msg
     * @return
     */
    @GetMapping("/sseSendMsgToOne")
    public String sendMessageToOne(String userId,String msg){
        MyWebSocketServer.sendOneMessage(userId,msg);
        return userId+"-->"+msg;
    }

    /**
     * http://localhost:8080/rainbow/sseSendMsgToMore
     * ?msg=7w77hiqwe51we1&userIds=926,9267
     *
     * 对多人发送同一条消息
     * @param userIds
     * @param msg
     * @return
     */
    @GetMapping("/sseSendMsgToMore")
    public String sseSendMsgToMore(@RequestParam("userIds") String[] userIds,String msg){
        MyWebSocketServer.sendMoreMessage(userIds,msg);
        return userIds[0]+"-->"+msg;
    }


    /**
     * 高端玩法-- 枚举参数解析
     * 1.参数直接映射到枚举，
     * 一般系统中的枚举/状态机相关的API  比较多时才会用
     * 2.GET传参映射到枚举时，springMvc根据enum.valueOf()来解析的
     *
     *
     */
    public enum TYPE {
        A, B, C;
    }
// http://localhost:8080/rainbow/enum?type=A
    //  {"code":1000,"msg":"操作成功","data":"A","timestamp":1600570609528}
    @GetMapping(path = "enum")
    public String enumParam(TYPE type) {
        return type.name();
    }

    //http://localhost:8080/rainbow/enum2?type=FAILED
    //  {"code":1000,"msg":"操作成功","data":1001,"timestamp":1600571036977}
    @GetMapping(path = "enum2")
    public int enumParam2(@RequestParam ResultCodeEnum type) {
        return type.getCode();
    }


    /**
     * req bean风格的api
     * 适合需要大量参数的req
     * 企业中用的多
     *
     * http://localhost:8080/rainbow/bean?name=yihuihui&age=18&uIds=1,3,4
     * {"code":1000,"msg":"操作成功","data":{"name":"yihuihui","age":18,"uids":[1,3,4]},"timestamp":1600568945340}
     *
     * http://localhost:8080/rainbow/bean?name=yihuihui&age=18
     * {"code":1000,"msg":"操作成功","data":{"name":"yihuihui","age":18,"uids":null},"timestamp":1600568968664}
     *
     * @param req
     * @return
     */
    @GetMapping(path = "bean")
    public TestReq beanParam(TestReq req) {
        return req;
    }

    /**
     * PathVariable风格的req
     * 不适合参数太多的情况，一般仅在查询单条数据用
     * http://localhost:8080/rainbow/pvt/qwe/12
     *
     * {"code":1000,"msg":"操作成功","data":"name: qwe index: 12","timestamp":1600568394665}
     *
     * @param name
     * @param index
     * @return
     */
    @GetMapping(path = "pvt/{name}/{index}")
    public String urlParam(@PathVariable(name = "name") String name,
                           @PathVariable(name = "index", required = false) Integer index) {
        return "name: " + name + " index: " + index;
    }


    /**
     * 方法参数式的API
     * 将GET参数与方法的参数根据参数名进行映射，从感官上来看，就像是直接调用这个一样
     *
     方法参数与GET传参，通过参数签名进行绑定
     方法参数类型，需要与接收的GET传参类型一致
     方法参数非基本类型时，若传参没有，则为null；（也就是说如果为基本类型，无法转null，抛异常）
     实际的GET传参可以多于方法定义的参数，但是多传的参数，无法被解析
     * @param name
     * @param age
     * @return
     */
    @GetMapping(path = "/zh")
    public String testChineseCode(String name, Integer age) {
        String an = "name: " + name + " age: " + age;
        System.out.println(an);
        return an;
    }

    /**
     * 传数组时参数值用逗号分隔；基本类型，必须传参，否则解析异常
     * /arg2?name=yihui,erhui&size=2'
     *
     * @param names
     * @param size
     * @return
     */
    @GetMapping(path = "arg2")
    public String argParam2(String[] names, int size) {
        return "name: " + (names != null ? Arrays.asList(names) : "null") + " size: " + size;
    }

    /**
     * RequestParam风格的api
     * name属性为参数别名
     * required属性为是否必填/必传 （默认为都必传）
     *
     * 1.相比用直接方法参数，更灵活，更规范，可以对每个参数做精细化控制
     * 2.api req参数名可以与内部真实的 字段名不一致，springMvc会帮你转换，
     * 即 对外暴漏的系统请求参数 name 与系统真实业务字段 uname ，最终的值一样的，
     * 这样对外围系统/第三方系统的兼容性好，更便于外围系统理接本系统的api 参数含义
     * 3.不建议在参数较多的情况下使用，因为字段太多开发时方便，维护时困难
     *
     *
     * http://localhost:8080/rainbow/ano?name=yihuihui&age=18&uids=123,234,324
     *
     * {"code":1000,"msg":"操作成功","data":"name: yihuihui age: 18 uids: [123, 234, 324]","timestamp":1600570144712}
     *
     *
     * @param uname
     * @param age
     * @param uids
     * @return
     */
    @GetMapping(path = "ano")
    public String anoParam(@RequestParam(name = "name") String uname,
                           @RequestParam(name = "age", required = false) Integer age,
                           @RequestParam(name = "uids", required = false) Integer[] uids) {
        return "name: " + uname + " age: " + age + " uids: " + (uids != null ? Arrays.asList(uids) : "null");
    }




    private int[] ans = new int[]{1, 2, 3, 4};

    @GetMapping(path = "ary")
    public int ary(int index) {
        return ans[index];
    }


    /**
     * 伪造一个返回大Json的Req
     *
     * @return
     */
    @GetMapping("bigReq")
    public String bigReqList() {
        List<String> result = new ArrayList<>(2048);
        for (int i = 0; i < 2048; i++) {
            result.add(UUID.randomUUID().toString());
        }
        return JSON.toJSONString(result);
    }

    /**
     * RestController风格的重定向
     * <p>
     * 请求http://localhost:8080/rainbow/r2
     * 时Status Code = 302
     * 会自动重定向到 http://localhost:8080/rainbow/bigReq
     *
     * @param response
     * @throws IOException
     */
    @ResponseBody
    @GetMapping(path = "r2")
    public void r2(HttpServletResponse response) throws IOException {
        String redirectStr = serverProperties.getServlet().getContextPath() + "/bigReq";
        response.sendRedirect(redirectStr);
    }
}
